package com.school.information.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.school.information.core.constant.CommonConstant;
import com.school.information.core.exception.ServiceException;
import com.school.information.core.service.RedisService;
import com.school.information.dto.RoleDTO;
import com.school.information.entity.SysRoleEntity;
import com.school.information.entity.SysRoleMenuEntity;
import com.school.information.enums.result.SysResultEnum;
import com.school.information.enums.status.EnabledEnum;
import com.school.information.mapper.SysRoleMapper;
import com.school.information.qo.SysRoleQO;
import com.school.information.service.SysRoleMenuService;
import com.school.information.service.SysRoleService;
import com.school.information.utils.GenrateCodeUtil;
import com.school.information.utils.UserUtil;
import com.school.information.vo.RoleVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRoleEntity> implements SysRoleService {
    @Resource
    private SysRoleMapper roleMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private SysRoleMenuService roleMenuService;

    @Override
    public Set<String> findRoleByUserId(Long userId) {
        Set<String> roles = new HashSet<String>();
        // 管理员拥有所有权限
        if (UserUtil.isAdmin(userId)) {
            roles.add("admin");
        } else {
            List<SysRoleEntity> roleList = roleMapper.findByUserId(userId);
            for (SysRoleEntity role : roleList) {
                if (Objects.nonNull(role)) {
                    roles.addAll(Arrays.asList(role.getCode().trim().split(",")));
                }
            }
        }
        return roles;
    }

    @Override
    public Set<Long> findRoleIdByUserId(Long userId) {
        Set<Long> roleIds = new HashSet<Long>();
        List<SysRoleEntity> roleList = roleMapper.findByUserId(userId);
        roleIds = roleList.stream().map(SysRoleEntity::getId).collect(Collectors.toSet());
        return roleIds;
    }

    @Override
    public IPage<SysRoleEntity> pageList(SysRoleQO sysRole) {
        LambdaQueryWrapper<SysRoleEntity> queryWrapper = Wrappers.<SysRoleEntity>query().lambda().orderByDesc(SysRoleEntity::getCreateTime);
        if (StringUtils.isNotBlank(sysRole.getName())) {
            queryWrapper.like(SysRoleEntity::getName, sysRole.getName());
        }
        if (StringUtils.isNotBlank(sysRole.getCode())) {
            queryWrapper.eq(SysRoleEntity::getCode, sysRole.getCode());
        }
        return this.page(new Page<>(sysRole.getCurrent(), sysRole.getSize()), queryWrapper);
    }

    @Override
    public String getMaxCode() {
        // 当 redis中不存在key时 会自动新增一个key  默认值为0
//        redisService.incr(CommonConstant.PREFIX_ROLE_CODE, 1);
        String newCode = "";
        if (!redisService.hasKey(CommonConstant.PREFIX_ROLE_CODE)) {
            redisService.incr(CommonConstant.PREFIX_ROLE_CODE, 1);
        }
        newCode = GenrateCodeUtil.getNewAutoNum(CommonConstant.PREFIX_ROLE_CODE, 3, (int) redisService.get(CommonConstant.PREFIX_ROLE_CODE));
        return newCode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveInfo(RoleDTO roleDTO) {
        boolean result = false;
        SysRoleEntity role = roleDTO.getSysRole();
        // 验证角色编码、名称是否存在
        SysRoleEntity roleCode = getByCode(role.getCode());
        if (Objects.nonNull(roleCode) && StringUtils.isNotBlank(roleCode.getCode())) {
            log.error("##角色编码{}已存在", roleCode.getCode());
            throw new ServiceException(SysResultEnum.ROLE_KEY_EXISTED);
        }
        SysRoleEntity roleName = getByName(role.getName());
        if (Objects.nonNull(roleName) && StringUtils.isNotBlank(roleName.getName())) {
            log.error("##角色名称{}已存在", roleName.getName());
            throw new ServiceException(SysResultEnum.ROLE_NAME_EXISTED);
        }
        try {
            // 默认启用
            role.setIsEnabled(EnabledEnum.ENABLE);
            result = this.save(role);
            if (result && !CollectionUtils.isEmpty(roleDTO.getMenus())) {
                // 插入成功后，角色编码自增1
                redisService.incr(CommonConstant.PREFIX_ROLE_CODE, 1);
                // 插入角色和菜单关系信息
                saveOrUpdateRoleMenu(role.getId(), roleDTO.getMenus());
            }
        } catch (DuplicateKeyException e) {
            log.error("##唯一索引异常");
            throw new ServiceException(SysResultEnum.ROLE_UK_INDEX_EXCEPTION);
        }
        return result;
    }

    @Override
    public SysRoleEntity getByCode(String code) {
        return this.getOne(Wrappers.<SysRoleEntity>lambdaQuery().eq(SysRoleEntity::getCode, code));
    }

    @Override
    public SysRoleEntity getByName(String name) {
        return this.getOne(Wrappers.<SysRoleEntity>lambdaQuery().eq(SysRoleEntity::getName, name));
    }

    @Override
    public RoleVO getInfoById(Long id) {
        SysRoleEntity role = this.getById(id);
        List<Long> menuIds = roleMenuService.findByRoleId(role.getId());
        RoleVO roleVO = new RoleVO();
        BeanUtils.copyProperties(role, roleVO);
        roleVO.setMenus(menuIds);
        return roleVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateInfo(RoleDTO roleDTO) {
        boolean result = false;
        SysRoleEntity role = roleDTO.getSysRole();
        SysRoleEntity oldRole = this.getById(role.getId());
        // 验证角色编码、名称是否存在
        SysRoleEntity roleCode = getByCode(role.getCode());
        if (Objects.nonNull(roleCode) && StringUtils.isNotBlank(roleCode.getCode())
                && !roleCode.getCode().equals(oldRole.getCode())) {
            log.error("##角色编码{}已存在", roleCode.getCode());
            throw new ServiceException(SysResultEnum.ROLE_KEY_EXISTED);
        }
        SysRoleEntity roleName = getByName(role.getName());
        if (Objects.nonNull(roleName) && StringUtils.isNotBlank(roleName.getName())
                && !roleName.getName().equals(oldRole.getName())) {
            log.error("##角色名称{}已存在", roleName.getName());
            throw new ServiceException(SysResultEnum.ROLE_NAME_EXISTED);
        }
        oldRole.setName(role.getName()).setRemark(role.getRemark());
        result = this.updateById(oldRole);
        if (result) {
            // 插入角色和菜单关系信息
            saveOrUpdateRoleMenu(role.getId(), roleDTO.getMenus());
        }
        return result;
    }

    @Override
    public boolean updateStatus(Long id, EnabledEnum enable) {
        SysRoleEntity oldRole = getById(id);
        oldRole.setIsEnabled(enable);
        return updateById(oldRole);
    }

    @Override
    public List<SysRoleEntity> findList() {
        return this.list(Wrappers.<SysRoleEntity>lambdaQuery().eq(SysRoleEntity::getIsEnabled, EnabledEnum.ENABLE));
    }

    /**
     * 保存或更新角色菜单信息
     *
     * @param roleId
     * @param menuIds
     */
    private void saveOrUpdateRoleMenu(Long roleId, List<Long> menuIds) {
        // 根据角色id，删除角色菜单信息
        roleMenuService.delByRoleId(roleId);
        List<SysRoleMenuEntity> list = new LinkedList<>();
        menuIds.forEach(menuId -> {
            list.add(new SysRoleMenuEntity().setRoleId(roleId).setMenuId(menuId));
        });
        roleMenuService.saveBatch(list);
    }
}
